class User < ActiveRecord::Base

  hobo_model

  include Hobo::AuthenticatedUser
  
  set_login_attr :email
  
  alias_attribute :display_name, :email

  # Owned elections
  has_many :owned_elections, :class_name => 'Election', :dependent => :nullify

  # Voting ballots and voting elections
  has_many :ballots, :dependent => :nullify
  has_many :voting_elections, :class_name => 'Election', :through => :ballots, :source => :election

  attr_accessible :login, :email, :password, :password_confirmation

  # --- Validation --- #
  
  validates_presence_of :email
  validates_uniqueness_of :email  
  validates_inclusion_of :admin, :in => [true, false], :allow_nil => true
  validates_length_of :email, :in => 5..64
  validates_format_of :email, :with => /(^([^@\s]+)@((?:[-_a-z0-9]+\.)+[a-z]{2,})$)|(^$)/i

  # --- Hobo Permissions --- #

  # Disable permission bypassing
  def super_user?
    false
  end
  
  def super_admin?
    admin? and 1 == id
  end

  def creatable_by?(creator)
	  creator.super_admin?
  end

  def updatable_by?(updater, new)
	  updater.super_admin?
  end

  def deletable_by?(deleter)
	  false
  end

  def viewable_by?(viewer, field)
	  viewer == self or viewer.admin?
  end

  def self.public_signups?
    return false
  end

  # --- Fallback permissions --- #

  # (Hobo checks these for models that do not define the *_by? methods)

  def can_create?(obj)
	  false
  end

  def can_update?(obj, new)
	  false
  end

  def can_delete?(obj)
	  false
  end

  def can_view?(obj, field)
	  true
  end

  def guest?
	  false
  end
  
  # --- Class methods --- #
  
  def self.find_or_create(email)
	user = find_by_email(email)
  	if user.nil?
  	  user = Hobo.user_model.new
      password = generate_password
      user.email = email
      user.password = password
      user.password_confirmation = password
      user.save!
      Notifier.deliver_signup(user, password)
    end
    return user
  end
  
  # Generate a random password
  def self.generate_password(length = 8)
    chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('1'..'9').to_a - ['o', 'O', 'i', 'I']
    Array.new(length) { chars[rand(chars.size)] }.join
  end

  # --- Instance methods --- #
  
  def cast_vote(election, candidate)
    # Get the ballot
    ballot = Ballot.find_valid(self,election)

    # Create the vote, cast it and invalidate the ballot
    vote=nil
    transaction do
      vote = Vote.cast!(self,election,candidate,ballot)
    end
    
    return vote
  end
  
  def get_voted_elections
      voted_elections = Array.new
      ballots.each do |ballot|
        voted_elections << ballot.election if ballot.cast?
      end
      voted_elections
  end
  
  def get_unvoted_elections
      unvoted_elections = Array.new
      ballots.each do |ballot|
        unvoted_elections << ballot.election unless ballot.cast?
      end
      unvoted_elections
  end

  def didnt_vote(election)
      get_unvoted_elections.each do |possible_election|
        return true if possible_election == election
      end
      return false
  end
   
  def reset_password
    new_pass = User.generate_password
    self.password = new_pass
    self.password_confirmation = new_pass
    save!
    Notifier.deliver_reset_password(email,new_pass)
  end 
end
